#!/bin/bash
#
# Version Controlled Changes
# System for LinuxLive/Slax
# Copyright       : (C) 2008 some-guy
# E-mail          : muhammedu (at) gmail (dot) com 
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# == set some paths and import functions
PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
. /etc/rc.d/init.d/functions 
. /mnt/live/liblinuxlive 

# == bail
function error_bail {
	echo "ERROR:"
	echo "$@"
	echo "Exiting..."
	echo "---------------------------------------------"
	exit 1
}


# == define some values
MOUNT_VCC=/vcchanges
CHANGES_DIR=/mnt/live/memory/changes
MODULES_DIR=/mnt/live/memory/modules
VCCVAL=$(cmdline_value vcchanges)
TMP=/tmp
DB_FILES=$TMP/changes.db

# == bail if vcchanges is not used
if [ ! -z $VCCVAL ]; then 
	VCCMNT=$(find_in_computer $VCCVAL)
else
	error_bail "Cannot use $VCCVAL"
fi

# == find what to control
if [ -f $VCCMNT/vcchanges.conf ]; then
	CONTROLLED_DIRS=$(cat $VCCMNT/vcchanges.conf | grep CONTROLLED_DIRS | sed -e s/CONTROLLED_DIRS=//)
else
	CONTROLLED_DIRS="root home usr/local opt"
fi

mkdir -p $MOUNT_VCC

if [ -d $VCCMNT ]; then
	# == bind actual location to /vcchanges
	mount --bind $VCCMNT $MOUNT_VCC
elif [ -f $VCCMNT ]; then
	# == loopmount the file to /vcchanges
	mount -n -o users,suid,dev,exec,loop $VCCMNT $MOUNT_VCC
else
	error_bail "Cannot use $VCCMNT"
fi

# == update all other file types
function update_other {
	for y in $CONTROLLED_DIRS; do
		OLDDIR=`pwd`
		# == make sure directory exists
		CHANGES_CONTROLLED_DIR="$MOUNT_VCC/changes/$y"
		[ -d $CHANGES_CONTROLLED_DIR ] || mkdir -p $CHANGES_CONTROLLED_DIR
		for a in `find $CHANGES_DIR/$y -type f`; do
			if [ -z "$(file $a | grep text)" ]; then
				# == derive some more info
				FILE_PATH=`echo $a | sed -e s,$CHANGES_DIR/$y,,`
				FILE_BASENAME=`echo $FILE_PATH | xargs basename`
				FOLDER_PATH=`echo $FILE_PATH | sed -e s,$FILE_BASENAME,,`
				# == make the file's path and copy
				mkdir -p $CHANGES_CONTROLLED_DIR/$FOLDER_PATH; cp $a $MOUNT_VCC/changes/$y/$FOLDER_PATH/
			fi; done
		# == make sure all the files exist, and make a db of the files recorded
		if [ -f $DB_FILES ]; then
			for file_other in $(cat $DB_FILES); do
				[ -e /$fileother ] || rm -rf $MOUNT_VCC/changes/$file_other
			done; fi
		find $MOUNT_VCC/changes/ | sed -e s,$MOUNT_VCC/changes/,, >$DB_FILES
	done
}


# == infinite loop of changes
function vcc_loop {
	# == get the time
	NOW_DAY=`date +%F`
	# == start the infinite loop until it is time to zzzzzz
	while true; do
		# == wait for 8 minutes
		sleep 480
		for s in $CONTREOLLED_DIRS; do
			OLDDIR=`pwd`
			cd /$s
			# == git-add all text files and folders
			for c in `find $CHANGES_DIR/$s`; do
				# == check for file/folder
				if [ -d $c ] || [ ! -z "$(file $c | grep text)" ]; then
					git-add $(echo $c | sed -e s,$CHANGES_DIR/$s/,,)
				fi
			done
			# == diff and commit
			DIFF_FILE="$MOUNT_VCC/patches/$s/diff-$NOW_DAY.vcchange"
			[ -d $MOUNT_VCC/patches ] || mkdir -p $MOUNT_VCC/patches/$s
			[ ! -f $DIFF_FILE.gz ] || rm -rf $DIFF_FILE.gz
			git-diff >$DIFF_FILE
			# == compress the diff
			gzip $DIFF_FILE
			# == check if the day changed
			if [ x`date +%F` != x$NOW_DAY ]; then
				git-commit -m "commit $(date +%T)"
				NOW_DAY=`date +%F`
			fi
			cd $OLDDIR
		done
		update_other; done
}


# == set up dirs
for g in $CONTROLLED_DIRS; do
	# == check for git
	if [ -f "`which git`"]; then
		# == initial startup 
		OLDDIR=`pwd`
		cd /$g
		git-init
		# == git-add all text files and folders
		for c in `find .`; do
			# == check for file/folder
			if [ -d $c ] || [ ! -z "$(file $c | grep text)" ]; then
				git-add $c
			fi
		done
		# == commit
		git-commit -m "commit $(date +%T)"
		cd $OLDDIR
	else
		error_bail "git is not installed"
	fi
	for folder in "patches changes modules"; do
		[ -d $MOUNT_VCC/$folder ] || mkdir -p $MOUNT_VCC/$folder
	done
	cd /
	# == apply previous changes
	for diff_vcc in `find $MOUNT_VCC/patches -type f | grep .vcchange`; do patch -p1 < $diff_vcc &>/dev/null; done
	rsync -ua $MOUNT_VCC/changes /
	# == bind modules folder
	rsync -ua $MODULES_DIR $MOUNT_VCC/modules
	rm -rf $MODULES_DIR
	mount --bind $MOUNT_VCC/modules $MODULES_DIR
	for module in `find $MODULES_DIR -type f`; do activate $module &>/dev/null; done
done

vcc_loop &
